/*******************************************************************************
 * Copyright (c) 2012, 2013 XML-Print Project.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     XML-Print Project - initial API and implementation
 ******************************************************************************/
package info.xmlprint.ui.format;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

import info.xmlprint.core.format.Format;
import info.xmlprint.core.format.FormatGroup;
import info.xmlprint.core.project.PrintProject;
import info.xmlprint.run.Constants;
import info.xmlprint.run.RuntimeUtil;
import info.xmlprint.ui.message.GuiMessages;
import info.xmlprint.ui.stileditor.StileditorViewer;
import info.xmlprint.ui.widgets.IObserverControl;
import info.xmlprint.ui.widgets.ISetupComposite;
import info.xmlprint.ui.widgets.ISubjectControl;
import info.xmlprint.util.ResizeColumns;

import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TreeEditor;
import org.eclipse.swt.custom.ViewForm;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.swt.widgets.Widget;

/*
 * FormatGroup einstellen
 */
public class FormatGroupSetup extends Composite implements IObserverControl,
		ISubjectControl, ISetupComposite {

	private FormatGroupSetup _this = this;

	private FormatGroup formatGroup;

	private TreeViewer formatTreeViewer;

	private PrintProject printProject;

	private List<IObserverControl> observerList = new ArrayList<IObserverControl>();

	public FormatGroupSetup(Composite parent, int style) {
		super(parent, style);
		this.setLayout(new FillLayout());
		createControls();
	}

	private void controlAddCreateFormatAction(Widget widget, final Format format) {

		final Tree tree = formatTreeViewer.getTree();
		widget.addListener(SWT.Selection, new Listener() {
			public void handleEvent(Event event) {
				TreeItem item = null;
				if (format != null)
					item = formatTreeViewer.getTree().getSelection()[0];
				else {
					item = new TreeItem(tree, SWT.NONE);
					tree.select(item);
				}
				TreeEditor editor = new TreeEditor(tree);
				editor.horizontalAlignment = SWT.LEFT;
				editor.grabHorizontal = true;
				final Text text = new Text(tree, SWT.NONE);

				if (format == null) {
					HashSet<String> nameSet = new HashSet<String>();
					for (TreeItem it : tree.getItems()) {
						nameSet.add(it.getText());
					}
					String newName = GuiMessages.Stileditor_Gui_Format_new;
					int nameIndex = 1;
					while (nameSet.contains(newName)) {
						newName = GuiMessages.Stileditor_Gui_Format_new + "_"
								+ nameIndex;
						nameIndex++;
					}
					text.setText(newName);
				} else
					text.setText(format.getName());

				// FontData fontData = text.getFont().getFontData()[0];
				// Font font = new Font(text.getDisplay(), new FontData(fontData
				// .getName(), fontData.getHeight(), SWT.ITALIC));
				// text.setFont(font);
				text.setBackground(tree.getDisplay().getSystemColor(
						SWT.COLOR_YELLOW));

				text.addListener(SWT.FocusOut, new Listener() {
					public void handleEvent(Event e) {
						createFormatAction(text, format);
					}
				});

				text.addListener(SWT.Verify, new Listener() {
					public void handleEvent(Event e) {
						// String string = e.text;
						// if (string.matches(".*[^a-zäöüßA-ZÄÖÜ0-9_\\s]+.*"))
						// e.doit = false;
						return;
					}
				});

				text.addKeyListener(new KeyAdapter() {
					public void keyPressed(KeyEvent event) {
						switch (event.keyCode) {
						case SWT.CR:
							createFormatAction(text, format);
							break;
						case SWT.ESC:
							text.dispose();
							break;

						}
					}
				});

				editor.setEditor(text, item);
				text.setFocus();
				text.selectAll();
			}
		});

	}

	public void createControls() {

		final ViewForm viewForm = new ViewForm(this, SWT.NONE);
		viewForm.setLayout(new FillLayout());

		Composite headComp = new Composite(viewForm, SWT.FLAT);
		formatTreeViewer = new TreeViewer(viewForm, SWT.FULL_SELECTION
				| SWT.MULTI);

		headComp.setLayoutData(createGridData(GridData.FILL_HORIZONTAL, null,
				30));
		headComp.setLayout(new GridLayout(6, false));

		Button neuFormatButton = new Button(headComp, SWT.NONE);
		Image newImg = new Image(null, this.getClass().getResourceAsStream(
				Constants.MAPPING_NEW_IMG));
		neuFormatButton.setImage(newImg);

		neuFormatButton.setToolTipText(GuiMessages.Stileditor_Gui_Format_new);
		
		/*
		Button saveButton = new Button(headComp, SWT.NONE);

		Image saveImg = new Image(null, this.getClass().getResourceAsStream(
				Constants.MAPPING_SAVE_IMG));

		saveButton.setImage(saveImg);
		saveButton.setToolTipText(GuiMessages.Stileditor_Gui_Format_save);
		saveButton.addListener(SWT.Selection, new Listener() {
			public void handleEvent(Event e) {
				FileDialog dialog = new FileDialog(viewForm.getShell(),
						SWT.SAVE);
				dialog.setFilterNames(new String[] { ".xml" });
				dialog.setFilterExtensions(new String[] { "*.xml", "*.*" });

				String filePath = dialog.open();

				if (filePath != null) {
					if (formatGroup.saveToXml(filePath))
						MessageDialog.openInformation(null, "",
								GuiMessages.General_Gui_Formats + " "
										+ GuiMessages.General_Gui_Save_Success
										+ " in " + filePath);
					else
						MessageDialog.openInformation(null, "",
								GuiMessages.Stileditor_Error_ErrorSaving + " "
										+ GuiMessages.General_Gui_Formats
										+ " in " + filePath);
				}
			}
		});

		Button openButton = new Button(headComp, SWT.NONE);
		Image openImg = new Image(null, this.getClass().getResourceAsStream(
				Constants.MAPPING_OPEN_IMG));
		openButton.setImage(openImg);
		openButton.setToolTipText(GuiMessages.Stileditor_Gui_Format_open);
		openButton.addListener(SWT.Selection, new Listener() {
			public void handleEvent(Event e) {
				FileDialog dialog = new FileDialog(viewForm.getShell(),
						SWT.OPEN);
				dialog.setFilterNames(new String[] { ".xml" });
				dialog.setFilterExtensions(new String[] { "*.xml", "*.*" });

				String filePath = dialog.open();

				if (filePath != null) {
					FormatGroup newFg = FormatGroup.readFile(filePath);
					if (newFg != null) {
						ImportSetupViewer impSetup = new ImportSetupViewer(
								formatGroup, newFg, printProject);
						impSetup.registerObserver(_this);
						impSetup.Open();
					}
				}
			}
		});*/
		Label label = new Label(headComp, SWT.NONE);
		label.setLayoutData(createGridData(GridData.FILL_BOTH, null, null));

		/*
		 * // Inhalt von allen Formaten anzuzeigen Button infoButton = new
		 * Button(headComp, SWT.NONE); infoButton.setText("?");
		 * infoButton.setToolTipText
		 * (GuiMessages.Stileditor_Gui_Tooltip_Formats);
		 * infoButton.addSelectionListener(new SelectionAdapter() { public void
		 * widgetSelected(SelectionEvent e) {
		 * showInfo(XmlUtil.doc2IndentString(formatGroup.getXmlDoc()));
		 * 
		 * } });
		 */

		final Tree tree = formatTreeViewer.getTree();
		tree.setHeaderVisible(true);
		tree.setLinesVisible(true);
		TableLayout tableLayout = new TableLayout();
		tree.setLayout(tableLayout);
		tree.setLayoutData(new GridData(GridData.FILL_BOTH));

		// "Formats" Column
		// tableLayout.addColumnData(new ColumnWeightData(150));
		new TreeColumn(tree, SWT.CHECK | SWT.CENTER)
				.setText(GuiMessages.Stileditor_Gui_Formats);

		formatTreeViewer.setContentProvider(new ITreeContentProvider() {
			@Override
			public void dispose() {
			}

			@Override
			public Object[] getChildren(Object parentElement) {
				return null;
			}

			@Override
			public Object[] getElements(Object inputElement) {
				if (inputElement instanceof FormatGroup) {
					return ((FormatGroup) inputElement).getFormats();
				}
				return null;
			}

			@Override
			public Object getParent(Object element) {
				return null;
			}

			@Override
			public boolean hasChildren(Object element) {
				return false;
			}

			@Override
			public void inputChanged(Viewer viewer, Object oldInput,
					Object newInput) {
			}
		});

		// LabelProvider
		formatTreeViewer.setLabelProvider(new ITableLabelProvider() {

			@Override
			public void addListener(ILabelProviderListener listener) {
			}

			@Override
			public void dispose() {
			}

			@Override
			public Image getColumnImage(Object element, int columnIndex) {
				return null;
			}

			@Override
			public String getColumnText(Object element, int columnIndex) {
				if (element instanceof Format) {
					return ((Format) element).getName();
				}
				return null;
			}

			@Override
			public boolean isLabelProperty(Object element, String property) {
				return false;
			}

			@Override
			public void removeListener(ILabelProviderListener listener) {
			}
		});

		// Bei Doppelklick neues Format oder bestehendes bearbeiten
		tree.addListener(SWT.MouseDoubleClick, new Listener() {
			@Override
			public void handleEvent(Event e) {
				final IStructuredSelection selection = (IStructuredSelection) formatTreeViewer
						.getSelection();
				Format format = (Format) selection.getFirstElement();
				if (format == null) { // leere Zeile FUNTIONIERT SO NICHT
					// createFormat(this, null);
				} else {
					if (format.getType().equals("ignore"))
						MessageDialog
								.openError(
										null,
										GuiMessages.Stileditor_Info_Info,
										GuiMessages.Stileditor_Error_FormatUsed1
												+ " "
												+ format.getName()
												+ " "
												+ GuiMessages.Stileditor_Error_FormatIgnore);
					else {
						FormatSetup ns = new FormatSetup();
						ns.setInput(printProject, format);
						ns.open();
					}

				}
				return;
			}
		});

		// "Entf" löscht Format
		tree.addListener(SWT.KeyDown, new Listener() {
			@Override
			public void handleEvent(Event e) {
				final IStructuredSelection selection = (IStructuredSelection) formatTreeViewer
						.getSelection();
				switch (e.keyCode) {
				case SWT.DEL:
					for (Object obj : selection.toArray()) {
						Format format = (Format) obj;
						String formatName = format.getName();

						if (!format.getType().equals(""))
							continue;

						if (RuntimeUtil.getInstance().isFormatInUse(
								formatName,
								StileditorViewer.getInstance()
										.getPrintProject())) {
							MessageDialog
									.openError(
											null,
											null,
											GuiMessages.Stileditor_Error_FormatUsed1
													+ " "
													+ formatName
													+ " "
													+ GuiMessages.Stileditor_Error_FormatUsed2);
							continue;
						} else
							formatGroup.removeFormat(format);
					}

					updateControl();
					break;
				default:
				}
			}

		});

		tree.addListener(SWT.MenuDetect, new Listener() {
			public void handleEvent(Event event) {
				final IStructuredSelection selection = (IStructuredSelection) formatTreeViewer
						.getSelection();

				int selectCount = selection.size();

				final Format format = (Format) selection.getFirstElement();
				Menu menu = new Menu(tree.getShell(), SWT.POP_UP);
				MenuItem newItem = new MenuItem(menu, SWT.PUSH);
				newItem.setText(GuiMessages.Stileditor_Gui_Format_new);
				menu.setVisible(true);

				controlAddCreateFormatAction(newItem, format);

				if (format == null && selectCount < 1) {
					return;
				}

				new MenuItem(menu, SWT.SEPARATOR);

				// Format bearbeiten
				MenuItem editItem = new MenuItem(menu, SWT.PUSH);
				editItem.setText(GuiMessages.General_Gui_Edit);

				if (selectCount > 1 || format.getType().equals("ignore"))
					editItem.setEnabled(false);
				else
					editItem.setEnabled(true);

				editItem.addListener(SWT.Selection, new Listener() {
					public void handleEvent(Event e) {
						FormatSetup ns = new FormatSetup();
						ns.registerObserver(_this);
						ns.setInput(printProject, format);
						ns.open();
					}
				});

				// Format umbenennen
				final MenuItem renameItem = new MenuItem(menu, SWT.PUSH);
				renameItem.setText(GuiMessages.General_Gui_Rename);
				controlAddCreateFormatAction(renameItem, format);

				if (selectCount != 1) {
					renameItem.setEnabled(false);
				} else
					renameItem.setEnabled(true);

				/*
				 * // neue Format hinzufuegen final MenuItem addItem = new
				 * MenuItem(menu, SWT.PUSH); addItem.setText("neu");
				 * addItem.addListener(SWT.Selection, new Listener() { public
				 * void handleEvent(Event event) { createFormat(addItem, tv); }
				 * });
				 */

				// Format entfernen
				MenuItem delItem = new MenuItem(menu, SWT.PUSH);
				delItem.setText(GuiMessages.General_Gui_Delete);

				// Format standard und ignore duerfen nicht entfernt werden
				if (selectCount == 1 && !format.getType().equals("")) {
					delItem.setEnabled(false);
				} else
					delItem.setEnabled(true);

				delItem.addListener(SWT.Selection, new Listener() {
					@Override
					public void handleEvent(Event event) {

						for (Object obj : selection.toArray()) {
							Format format = (Format) obj;
							String formatName = format.getName();

							if (!format.getType().equals(""))
								continue;

							if (RuntimeUtil.getInstance().isFormatInUse(
									formatName,
									StileditorViewer.getInstance()
											.getPrintProject())) {
								MessageDialog
										.openError(
												null,
												null,
												GuiMessages.Stileditor_Error_FormatUsed1
														+ " "
														+ formatName
														+ " "
														+ GuiMessages.Stileditor_Error_FormatUsed2);
								continue;
							} else {
								formatGroup.removeFormat(format);
								updateControl();
							}
						}
					}
				});
			}
		});

		controlAddCreateFormatAction(neuFormatButton, null);

		viewForm.setContent(formatTreeViewer.getControl());
		viewForm.setTopLeft(headComp);
		viewForm.addControlListener(new ResizeColumns(viewForm, tree));

	}

	private void createFormatAction(Text text, Format format) {
		String name = text.getText();
		if (name.equals(""))
			return;

		Tree tree = formatTreeViewer.getTree();

		for (TreeItem it : tree.getItems()) {
			// Wenn Format rename
			if (format != null && it.getData().equals(format))
				continue;

			if (it.getText().equals(name)) {
				MessageDialog.openError(null, null,
						GuiMessages.Stileditor_Error_FormatExists);
				text.setFocus();
				text.selectAll();
				return;
			}
		}

		String newName = text.getText();
		if (format == null) {
			Format newFormat = new Format();
			newFormat.setType("");
			newFormat.setName(newName);
			formatGroup.addFormat(newFormat);

		} else
			format.setName(newName);

		text.dispose();
		updateControl();
	}

	private GridData createGridData(Integer x, Integer w, Integer h) {
		GridData gridData = null;
		if (x != null)
			gridData = new GridData(x);
		else
			gridData = new GridData();

		if (w != null)
			gridData.widthHint = w;
		if (h != null)
			gridData.heightHint = h;

		return gridData;
	}

	@Override
	public void notifyObservers() {
		for (IObserverControl o : observerList) {
			o.updateControl();
		}
	}

	@Override
	public void registerObserver(IObserverControl observer) {
		observerList.add(observer);
	}

	@Override
	public void removeObserver(IObserverControl observer) {
		observerList.remove(observer);
	}

	@Override
	public void setPrintProject(PrintProject pProject) {
		printProject = pProject;
		formatGroup = printProject.getFormatGroup();
		formatTreeViewer.setInput(formatGroup);
	}

	@Override
	public void updateControl() {
		formatTreeViewer.refresh();
	}

}
